<template>
	<view class="content">
		<view class="upload-section">
			<button @click="chooseImage" type="primary" :disabled="loading">选择图片</button>
			
			<view class="status-section">
				<view v-if="loading" class="status-message loading">识别中...</view>
				<view v-if="errorMessage" class="status-message error">{{errorMessage}}</view>
				<view v-if="faceResults.length" class="status-message success">
					检测到 {{faceResults.length}} 个人脸！
				</view>
			</view>
			
			<!-- 图片预览区域 -->
			<view class="preview-container" v-if="imageUrl">
				<!-- 原图 -->
				<view class="preview-box">
					<view class="preview-header">
						<text class="preview-title">原图</text>
						<text class="image-size">{{imageInfo.width}} x {{imageInfo.height}}</text>
					</view>
					<image :src="imageUrl" mode="aspectFit" class="preview-image"></image>
				</view>
				
				<!-- 人脸分析结果 -->
				<view v-for="(face, index) in faceResults" :key="index" class="face-result-box">
					<view class="preview-header">
						<text class="preview-title">人脸 #{{index + 1}}</text>
						<text class="confidence">置信度: {{(face.detection.score * 100).toFixed(1)}}%</text>
					</view>
					
					<!-- 人脸图片 -->
					<view class="face-image-section">
						<image :src="face.faceImage" mode="aspectFit" class="face-image"></image>
					</view>
					
					<!-- 年龄性别 -->
					<view class="feature-section" v-if="face.age">
						<view class="feature-item">
							<text class="feature-label">年龄</text>
							<text class="feature-value">{{Math.round(face.age)}} 岁</text>
						</view>
						<view class="feature-item">
							<text class="feature-label">性别</text>
							<text class="feature-value">
								{{formatGender(face.gender)}} ({{(face.genderProbability * 100).toFixed(1)}}%)
							</text>
						</view>
					</view>
					
					<!-- 表情分析 -->
					<view class="feature-section" v-if="face.expressions">
						<text class="section-title">表情分析</text>
						<view class="expressions-grid">
							<view v-for="(prob, expr) in face.expressions" :key="expr" 
								  class="expression-item" 
								  :style="{opacity: prob}">
								<text class="expression-label">{{formatExpression(expr)}}</text>
								<text class="expression-value">{{(prob * 100).toFixed(1)}}%</text>
							</view>
						</view>
					</view>
					
					<!-- 人脸特征点 -->
					<view class="feature-section" v-if="face.landmarks">
						<text class="section-title">检测到 {{face.landmarks.positions.length}} 个特征点</text>
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import FaceApiPlugin from './index.js'

// 创建插件实例并配置参数
const faceApi = new FaceApiPlugin({
	// 输入图片尺寸(必须是32的倍数)
	// 值越大精度越高,但速度越慢,建议范围:224~640
	inputSize: 320,
	
	// 人脸检测置信度阈值(0~1)
	// 值越大要求越严格,建议范围:0.3~0.7
	scoreThreshold: 0.3,
	
	// 人脸裁剪区域的边距(像素)
	// 值越大保留的背景区域越多
	padding: 80,
	
	// 是否返回人脸图片的base64数据
	returnBase64: true,
	
	// 是否提取人脸特征点(68个关键点)
	landmarks: true,
	
	// 是否识别表情(7种基本表情)
	expressions: true,
	
	// 是否识别年龄和性别
	ageGender: true,
	
	// 是否计算人脸特征向量(用于人脸对比)
	descriptor: true
})

// 状态变量
const imageUrl = ref('') // 原图片路径
const loading = ref(false) // 是否正在处理中
const errorMessage = ref('') // 错误提示信息
const faceResults = ref([]) // 人脸检测结果数组
const imageInfo = ref({ width: 0, height: 0 }) // 图片尺寸信息

// 表情类型映射
const expressionMap = {
	neutral: '中性', // 中性表情
	happy: '开心', // 高兴
	sad: '悲伤', // 悲伤
	angry: '生气', // 愤怒
	fearful: '害怕', // 恐惧
	disgusted: '厌恶', // 厌恶
	surprised: '惊讶' // 惊讶
}

// 性别类型映射
const genderMap = {
	male: '男',
	female: '女'
}

// 格式化表情名称
const formatExpression = (expr) => expressionMap[expr] || expr

// 格式化性别
const formatGender = (gender) => genderMap[gender] || gender

// 初始化插件
onMounted(async () => {
	try {
		await faceApi.init()
		console.log('插件初始化成功')
	} catch (error) {
		errorMessage.value = '模型加载失败:' + error.message
		console.error('插件初始化失败:', error)
	}
})

// 选择图片
const chooseImage = async () => {
	try {
		const [tempFilePath] = (await uni.chooseImage({
			count: 1,
			sizeType: ['compressed'],
			sourceType: ['album', 'camera']
		})).tempFilePaths
		
		await processImage(tempFilePath)
	} catch (error) {
		uni.showToast({
			title: '选择图片失败',
			icon: 'none'
		})
	}
}

// 处理图片
const processImage = async (filePath) => {
	if (!filePath) return
	
	loading.value = true
	errorMessage.value = ''
	faceResults.value = []
	
	try {
		// 获取图片信息
		const imgInfo = await uni.getImageInfo({ src: filePath })
		
		// 计算缩放比例
		// maxSize: 图片的最大边长限制,用于控制处理性能
		const maxSize = 640
		let scale = 1
		// 如果图片尺寸超过限制,按比例缩小
		if (imgInfo.width > maxSize || imgInfo.height > maxSize) {
			scale = maxSize / Math.max(imgInfo.width, imgInfo.height)
		}
		
		// 保存图片信息
		imageUrl.value = filePath
		imageInfo.value = {
			width: Math.round(imgInfo.width * scale),
			height: Math.round(imgInfo.height * scale)
		}
		
		// 创建图片元素
		const image = new Image()
		image.src = filePath
		await new Promise((resolve) => {
			image.onload = resolve
		})
		
		// 检测人脸
		const results = await faceApi.detectFaces(image)
		
		if (results && results.length > 0) {
			faceResults.value = results
		} else {
			errorMessage.value = '未检测到人脸，请重试'
		}
	} catch (error) {
		console.error('图片处理失败:', error)
		errorMessage.value = '图片处理失败，请重试'
	} finally {
		loading.value = false
	}
}
</script>

<style>
/* 基础布局样式 */
.content {
	padding: 20rpx;
}

.upload-section {
	margin-top: 30rpx;
}

.status-section {
	margin: 20rpx 0;
}

/* 状态消息样式 */
.status-message {
	padding: 16rpx;
	border-radius: 8rpx;
	text-align: center;
	margin: 10rpx 0;
}

.loading {
	background-color: #e3f2fd;
	color: #1976d2;
}

.error {
	background-color: #ffebee;
	color: #c62828;
}

.success {
	background-color: #e8f5e9;
	color: #2e7d32;
}

/* 预览区域基础样式 */
.preview-container {
	display: flex;
	flex-direction: column;
	gap: 30rpx;
	margin-top: 30rpx;
}

.preview-box {
	background: #f5f5f5;
	padding: 20rpx;
	border-radius: 16rpx;
}

.preview-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 20rpx;
}

.preview-title {
	color: #42b883;
	font-size: 28rpx;
	font-weight: bold;
}

.image-size {
	color: #666;
	font-size: 24rpx;
}

.preview-image {
	width: 100%;
	height: 400rpx;
	border: 4rpx solid #42b883;
	border-radius: 12rpx;
	background: white;
}

/* 新增样式 */
.face-result-box {
	background: #f5f5f5;
	padding: 20rpx;
	border-radius: 16rpx;
	margin-top: 30rpx;
}

.confidence {
	color: #1976d2;
	font-size: 24rpx;
}

.face-image-section {
	margin: 20rpx 0;
}

.face-image {
	width: 100%;
	height: 300rpx;
	border: 4rpx solid #42b883;
	border-radius: 12rpx;
	background: white;
}

.feature-section {
	background: white;
	padding: 20rpx;
	border-radius: 12rpx;
	margin-top: 20rpx;
}

.section-title {
	font-size: 28rpx;
	color: #333;
	margin-bottom: 16rpx;
	display: block;
}

.feature-item {
	display: flex;
	justify-content: space-between;
	padding: 12rpx 0;
	border-bottom: 2rpx solid #eee;
}

.feature-label {
	color: #666;
	font-size: 26rpx;
}

.feature-value {
	color: #42b883;
	font-size: 26rpx;
	font-weight: bold;
}

.expressions-grid {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 16rpx;
}

.expression-item {
	background: #e8f5e9;
	padding: 12rpx;
	border-radius: 8rpx;
	text-align: center;
}

.expression-label {
	display: block;
	color: #2e7d32;
	font-size: 24rpx;
	margin-bottom: 4rpx;
}

.expression-value {
	color: #1b5e20;
	font-size: 22rpx;
	font-weight: bold;
}
</style>
